package top.lingkang.finaloauth2.examplespringboot.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.jdbc.core.JdbcTemplate;
import top.lingkang.finaloauth2.entity.Oauth2Code;
import top.lingkang.finaloauth2.entity.UserDetails;
import top.lingkang.finaloauth2.server.annotation.EnableAuthorizationServer;
import top.lingkang.finaloauth2.server.auth.AuthDetailsService;
import top.lingkang.finaloauth2.server.client.ClientDetails;
import top.lingkang.finaloauth2.server.client.ClientDetailsService;
import top.lingkang.finaloauth2.server.client.ClientDetailsServiceBuilder;
import top.lingkang.finaloauth2.server.config.AuthorizationServerConfiguration;
import top.lingkang.finaloauth2.server.config.AuthorizationServerProperties;
import top.lingkang.finaloauth2.server.error.AuthServerUserException;
import top.lingkang.finaloauth2.server.store.TokenStore;
import top.lingkang.finaloauth2.server.store.impl.JdbcTokenStore;
import top.lingkang.finaloauth2.server.store.impl.RedisTokenStore;

import javax.servlet.http.HttpServletRequest;
import java.util.HashSet;
import java.util.Set;

/**
 * @author lingkang
 * Created by 2022/3/27
 */
@EnableAuthorizationServer
@Configuration
public class Oauth2ServerConfig extends AuthorizationServerConfiguration {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    protected void config(AuthorizationServerProperties config) {

        // config.setTokenMaxExpires(555L);
    }

    @Override
    protected void configClient(ClientDetailsServiceBuilder clients) {
        // 使用jdbc读取授权客户端
        // clients.useJdbc(jdbcTemplate.getDataSource());

        // 使用内存存储
        clients.inMemory().addClient("client_id")
                .secret("secret")
                .authorizedGrantTypes("password","code","refresh_token")
                .scope("scope")

                .addClient("my_client02")
                .secret("my_secret02")
                .authorizedGrantTypes("password","code","refresh_token")
                .scope("private")
        ;
    }

    @Bean
    public TokenStore tokenStore() {
        // return new JdbcTokenStore(jdbcTemplate.getDataSource());
        return new RedisTokenStore(redisTemplate);
    }

    @Bean
    public AuthDetailsService userDetailsService(){
        return new AuthDetailsService() {
            @Override
            public UserDetails loginUser(String username, String password, HttpServletRequest request) {
                // 账号密码认证，，，可替换为数据库查询
                if (!"final".equals(username)) {
                    throw new AuthServerUserException("用户名不存在！");
                } else if (!"final".equals(password)) {
                    throw new AuthServerUserException("密码错误！");
                }

                // 添加角色，，，可替换为数据库查询
                Set<String> auth = new HashSet<>();
                auth.add("user");
                auth.add("admin");
                UserDetails details = new UserDetails("final", auth);

                // 添加其它您想要带上的数据，可通过 资源客户端的 resourceServerHolder.getAccessToken() 获取
                // details.setData();
                return details;
            }

            @Override
            public Set<String> codeAuthorizationRole(Oauth2Code oauth2Code, ClientDetails clientDetails, HttpServletRequest request) {
                // 授权码模式返回的角色
                HashSet<String> role = new HashSet<>();
                role.add("authCode");
                return role;
            }
        };
    }

    /*// 您也可以自定义实现 ClientDetailsService
    @Bean
    public ClientDetailsService clientDetailsService(){
        // 您也可以通过实现 ClientDetailsService 进行手动查询客户端
        return new ClientDetailsService() {
            @Override
            public ClientDetails loadClientByClientId(String clientId) {
                // 读取数据库客户端信息
                ClientDetails clientDetails=new ClientDetails();
                // 查询数据库赋值
                // clientDetails.set
                return clientDetails;
            }
        };
    }*/
}
